/**
参考网址：https://blog.csdn.net/weixin_42776111/article/details/124018060
实现测距功能
官网用的案例是地图使用的 EPSG:3857， 如果我们改成 EPSG:4326，测量数据不准确，切记这一点
*/
<template>
    <div class="home">
        <div class="set">
            <button class="btn" @click="distance()">测距</button>
            <button class="btn" @click="cancal()">取消</button>
        </div>
        <div id="map" ref="map"></div>
    </div>
</template>

<script>
    import 'ol/ol.css';
    import Draw from 'ol/interaction/Draw';
    import Map from 'ol/Map';
    import Overlay from 'ol/Overlay';
    import View from 'ol/View';
    import { Circle as CircleStyle, Fill, Stroke, Style } from 'ol/style';
    import { XYZ, Vector as VectorSource } from 'ol/source';
    import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
    import { getLength } from 'ol/sphere';
    import * as olProj from "ol/proj";
    import { unByKey } from 'ol/Observable';

    var map = null

    var helpTooltipElement = null
    var feature = null;
    var helpTooltip = null;
    var draw = null;
    var measureTooltipElement = null;
    var measureTooltip = null;
    var listener = null;
    var mapMouseMove = null;

    export default {
        name: "CeLength",
        data() {
            return {
                drawLayers: [],//绘制多个图形
                drawElements: [],//绘制图形过程中的多个提示要素
            }
        },
        mounted() {
            this.initMap()
        },
        methods: {
            // 初始化地图
            initMap() {
                map = new Map({
                    layers: [
                        new TileLayer({
                            source: new XYZ({
                                url: "https://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}",
                            })
                        })
                    ],
                    target: 'map',
                    view: new View({
                        center: olProj.fromLonLat([104.912777, 34.730746]), //地图中心坐标
                        zoom: 5,
                        maxZoom: 18,
                        // projection: 'EPSG:4326', // 默认EPSG:3857
                        constrainResolution: true,  // 设置缩放级别为整数 
                        smoothResolutionConstraint: false,  // 关闭无级缩放地图
                    }),
                });
            },

            // 测距
            distance() {
                let source = new VectorSource()// 首先创建一个数据源，用来放置绘制过程中和绘制结束后的线段
                const layer = new VectorLayer({ // 添加一个图层，用来放置数据源，样式自己随便设置就可以了，我这里默认的官网
                    source: source,
                    style: new Style({
                        fill: new Fill({
                            color: 'rgba(255, 255, 255, 0.2)',
                        }),
                        stroke: new Stroke({
                            color: '#ffcc33',
                            width: 4,
                        }),
                        image: new CircleStyle({
                            radius: 7,
                            fill: new Fill({
                                color: '#ffcc33',
                            }),
                        }),
                    }),
                });

                mapMouseMove = map.on('pointermove', (ev) => { // 给地图添加一个鼠标移动事件
                    let helpMsg = '点击开始测量'// 默认开始的操作提示文本
                    if (feature) {// featuer 是全局的，判断有没有点击鼠标绘制过
                        helpMsg = '双击结束测量'// 如果之前点击绘制了就显示双击结束
                    }
                    helpTooltipElement.innerHTML = helpMsg; // 设置dom的提示文字
                    helpTooltip.setPosition(ev.coordinate); // 设置位置跟着鼠标走
                    helpTooltipElement.classList.remove('hidden')// 让他显示出来

                })

                map.getViewport().addEventListener('mouseout', function () {
                    helpTooltipElement.classList.add('hidden');
                });

                draw = new Draw({
                    source, // 这个数据源就是我们最开始的那个数据源，这是简写，实际上是 source:source,
                    type: 'LineString',// 绘制线
                    style: new Style({ // 绘制完成之前线的样式，这是官网的样式，需要的话自己可以修改成自己想要的样子
                        fill: new Fill({
                            color: 'rgba(255, 255, 255, 0.2)',
                        }),
                        stroke: new Stroke({
                            color: 'rgba(0, 0, 0, 0.5)',
                            lineDash: [10, 10],
                            width: 4,
                        }),
                        image: new CircleStyle({
                            radius: 5,
                            stroke: new Stroke({
                                color: 'rgba(0, 0, 0, 0.7)',
                            }),
                            fill: new Fill({
                                color: 'rgba(255, 255, 255, 0.2)',
                            }),
                        }),
                    }),
                });

                // 开始坚挺绘制
                draw.on('drawstart', (evt) => {
                    feature = evt.feature;// feature就是全局的

                    let tooltipCoord = evt.coordinate; // 鼠标当前的位置 

                    listener = feature.getGeometry().on('change', function (evt) {
                        const geom = evt.target;
                        let output = formatLength(geom);// 距离的格式
                        tooltipCoord = geom.getLastCoordinate(); // 设置鼠标位置改变后的实时位置
                        measureTooltipElement.innerHTML = output;// 设置提示框的内容，就是距离
                        measureTooltip.setPosition(tooltipCoord); // 设置距离提示框的位置
                    });
                });

                // 双击绘制完成
                draw.on('drawend', () => {
                    measureTooltipElement.className = 'ol-tooltip ol-tooltip-static';
                    measureTooltip.setOffset([0, -7]);
                    feature = null;
                    measureTooltipElement = null;
                    this.createMeasureTooltip();
                    unByKey(listener);
                });

                // 格式化长度
                const formatLength = function (line) {
                    const length = getLength(line);
                    let output;
                    if (length > 100) {
                        output = Math.round((length / 1000) * 100) / 100 + ' ' + 'km';
                    } else {
                        output = Math.round(length * 100) / 100 + ' ' + 'm';
                    }
                    return output;
                };

                this.createHelpTooltip() // 创建那个helpTooltipElement方法
                this.createMeasureTooltip()// 创建那个距离的提示框
                map.addLayer(layer)// 把图层添加到地图
                this.drawLayers.push(layer)
                map.addInteraction(draw); // draw 绑定到地图上面去
            },

            // 取消绘制
            cancal() {
                for (let i = 0; i < this.drawLayers.length; i++) {
                    map.removeLayer(this.drawLayers[i])
                }
                for (let i = 0; i < this.drawElements.length; i++) {
                    map.removeOverlay(this.drawElements[i])
                }
                this.drawLayers = []
                this.drawElements = []
                map.removeInteraction(draw)
                unByKey(mapMouseMove);
            },

            createMeasureTooltip() {
                if (measureTooltipElement) {
                    measureTooltipElement.parentNode.removeChild(measureTooltipElement);
                }
                measureTooltipElement = document.createElement('div');
                measureTooltipElement.className = 'ol-tooltip ol-tooltip-measure';
                measureTooltip = new Overlay({
                    element: measureTooltipElement,
                    offset: [0, -15],
                    positioning: 'bottom-center',
                    stopEvent: false,
                    insertFirst: false,
                });
                this.drawElements.push(measureTooltip)
                map.addOverlay(measureTooltip);
            },

            createHelpTooltip() {
                if (helpTooltipElement) {
                    helpTooltipElement.parentNode.removeChild(helpTooltipElement);
                }
                helpTooltipElement = document.createElement('div');
                helpTooltipElement.className = 'ol-tooltip hidden';
                helpTooltip = new Overlay({
                    element: helpTooltipElement,
                    offset: [15, 0],
                    positioning: 'center-left',
                });
                map.addOverlay(helpTooltip);
            },

        },
    };

</script>
<style scoped>
    .home {
        width: 100%;
        height: 100vh;
        background-color: aliceblue;
        position: relative;
    }

    #map {
        height: 100%;
        width: 100%;
    }

    .set {
        position: absolute;
        top: 0px;
        right: 0px;
        z-index: 99;
    }

    .btn {
        margin: 10px;
    }

    /deep/.hidden {
        display: none;
    }

    /deep/.ol-tooltip {
        position: relative;
        background: rgba(0, 0, 0, 0.5);
        border-radius: 4px;
        color: white;
        padding: 4px 8px;
        opacity: 0.7;
        white-space: nowrap;
        font-size: 12px;
        cursor: default;
        user-select: none;
    }

    /deep/.ol-tooltip-measure {
        opacity: 1;
        font-weight: bold;
    }

    /deep/.ol-tooltip-static {
        background-color: #ffcc33;
        color: black;
        border: 1px solid white;
    }

    /deep/.ol-tooltip-measure:before,
    /deep/.ol-tooltip-static:before {
        border-top: 6px solid rgba(0, 0, 0, 0.5);
        border-right: 6px solid transparent;
        border-left: 6px solid transparent;
        content: "";
        position: absolute;
        bottom: -6px;
        margin-left: -7px;
        left: 50%;
    }

    /deep/.ol-tooltip-static:before {
        border-top-color: #ffcc33;
    }
</style>